package com.filldream.fastboot.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.filldream.fastboot.base.entity.Account;
import com.filldream.fastboot.base.entity.WxConfig;
import com.filldream.fastboot.base.mapper.AccountMapper;
import com.filldream.fastboot.base.request.CheckCodeSTO;
import com.filldream.fastboot.base.request.app.account.ChangePhoneSTO;
import com.filldream.fastboot.base.request.app.account.ResetPwdSTO;
import com.filldream.fastboot.common.constant.FinalStr;
import com.filldream.fastboot.common.util.entity.wx.WxInitSTO;
import com.filldream.fastboot.base.request.app.account.PasswordLoginSTO;
import com.filldream.fastboot.base.response.app.AccountManagerDTO;
import com.filldream.fastboot.common.entity.B;
import com.filldream.fastboot.common.entity.ErrorCode;
import com.filldream.fastboot.common.entity.R;
import com.filldream.fastboot.common.util.entity.wx.WxUser;
import com.filldream.fastboot.core.cache.CacheUtil;
import com.filldream.fastboot.core.event.WxAppOpenUnionIdEvent;
import com.filldream.fastboot.core.manager.AccountManager;
import com.filldream.fastboot.core.manager.SmsRecordManager;
import com.filldream.fastboot.core.manager.WxConfigManager;
import com.filldream.fastboot.core.service.AccountService;
import com.filldream.fastboot.common.util.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * @author RickSun
 * @Description 用户实现层
 **/
@Service
@Transactional(rollbackFor = Exception.class)
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    @Autowired
    private WxConfigManager wxConfigManager;

    @Autowired
    private AccountManager accountManager;

    @Resource
    private AccountMapper accountMapper;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private SmsRecordManager smsRecordManager;


    @Override
    public R<AccountManagerDTO> wxLogin(WxInitSTO loginSTO){
        //最终返回的用户类
        String token = "";

        WxConfig wxConfig = wxConfigManager.selectByAppId(loginSTO.getAppId());
        loginSTO.setLoginType( wxConfig.getType() );
        loginSTO.setAppId( wxConfig.getAppId() );
        loginSTO.setAppSecret(wxConfig.getAppSecret());

        WxUser wxUser = WxUtil.getWxUser(loginSTO);
        if( loginSTO.checkSilent() ){
            wxUser.setCity(loginSTO.getCity());
            wxUser.setCountry(loginSTO.getCountry());
            wxUser.setHeadimgurl(loginSTO.getAvatarUrl());
            wxUser.setSex(loginSTO.getGender());
            wxUser.setProvince(loginSTO.getProvince());
            wxUser.setLanguage(loginSTO.getLanguage());
        }
        Assert.isNull( wxUser,ErrorCode.NO_LOGIN.reMsg() );
        Assert.isEmpty(wxUser.getUnionid(), ErrorCode.WECHAT_AUTH_ERR.reMsg(":微信"));
        wxUser.setAppId(wxConfig.getAppId());
        applicationContext.publishEvent(new WxAppOpenUnionIdEvent(wxUser));

        //缓存session_key用于获取手机号
        CacheUtil.delKey(wxUser.getUnionid());
        CacheUtil.cacheObj(wxUser.getUnionid(),wxUser);


        AccountManagerDTO accountManagerDTO = accountManager.selectByWxId(null,wxUser.getUnionid());

        Account nowAccount = new Account();
        //授权用户
        if(accountManagerDTO == null){
            nowAccount.setDel(0);
            nowAccount.setOepnId(wxUser.getOpenid());
            nowAccount.setUnionId(wxUser.getUnionid());
            nowAccount.setHeadImg(wxUser.getHeadimgurl());
            nowAccount.setNickname(wxUser.getNickname());
            nowAccount.setUnionId( wxUser.getUnionid() );
            nowAccount.setTelephone(wxUser.getPhone());
            Integer insert = accountMapper.insert(nowAccount);
            Assert.checkInteger(insert,ErrorCode.NO_LOGIN.reMsg());
            token  = CacheUtil.createToken(nowAccount.getId());
        }else{
            //手机号
            String telephone = accountManagerDTO.getTelephone();
            if(StringUtils.isBlank(telephone)){
                accountManagerDTO.setTelephone(wxUser.getPhone());
            }

            //用户是否禁用
            Integer status = accountManagerDTO.getStatus();
            if( status.equals(0) ){
                return R.fail("您的账号已被禁用");
            }
            token  = CacheUtil.createToken(accountManagerDTO.getId());
            nowAccount = TransferUtil.changeToObj(accountManagerDTO,Account.class);
        }
        nowAccount.setToken(token);
        accountManager.modify( TransferUtil.changeToObj(nowAccount,Account.class) );
        nowAccount.setOepnId(null);
        nowAccount.setPassword(null);
        return R.successd(TransferUtil.changeToObj(nowAccount,AccountManagerDTO.class));
    }


    @Override
    public R<AccountManagerDTO> login(PasswordLoginSTO passwordLoginSTO) {
        Account account = accountMapper.selectOne( new LambdaQueryWrapper<Account>()
                .eq(Account::getPassword,   EncryptUtil.md5Encode(passwordLoginSTO.getPassword(), FinalStr.getPwdKey()) )
                .eq(Account::getTelephone,passwordLoginSTO.getTelephone())
        );

        Assert.isNull(account, ErrorCode.PASSWORD_ERROR.reMsg());
        //用户是否禁用
        Integer status = account.getStatus();
        if( status.equals(0) ){
            return R.fail("您的账号已被禁用");
        }

        String token  = CacheUtil.createToken(account.getId());
        account.setToken(token);
        accountManager.modify( TransferUtil.changeToObj(account,Account.class) );
        return R.successd(TransferUtil.changeToObj(account,AccountManagerDTO.class));
    }

    @Override
    public B reset(ResetPwdSTO resetPwdSTO) {
        Assert.checkPwd( resetPwdSTO.getNewPassword() );
        CheckCodeSTO checkCodeSTO = TransferUtil.changeToObj(resetPwdSTO, CheckCodeSTO.class);
        checkCodeSTO.setType(1);
        B checkResult = smsRecordManager.checkCode(checkCodeSTO);
        if(!checkResult.isOk()){
            return checkResult;
        }

        //修改密码
        Account account = accountManager.selectByPhone(resetPwdSTO.getCellPhone());
        Assert.isNull( account, ErrorCode.USER_NOT_EXIST.reMsg());

        account.setPassword(EncryptUtil.md5Encode(resetPwdSTO.getNewPassword(), FinalStr.getPwdKey()));
        return accountManager.modify(account) ? B.success() : B.fail();
    }

    @Override
    public B changePhone(ChangePhoneSTO changePhoneSTO) {
        CheckCodeSTO checkCodeSTO = TransferUtil.changeToObj(changePhoneSTO, CheckCodeSTO.class);
        checkCodeSTO.setType(2);
        checkCodeSTO.setCellPhone(changePhoneSTO.getNewPhone());
        B checkResult = smsRecordManager.checkCode(checkCodeSTO);
        if(!checkResult.isOk()){
            return checkResult;
        }

        ///我
        Account me = accountManager.selectByPhone(changePhoneSTO.getOldPhone());
        Assert.isNull( me, ErrorCode.USER_NOT_EXIST.reMsg());

        //修改手机号
        Account account = accountManager.selectByPhone(changePhoneSTO.getNewPhone());
        Assert.checkBoolean( account == null , ErrorCode.TELEPHONE_EXIT.reMsg());

        me.setTelephone(changePhoneSTO.getNewPhone());
        return B.checkSuccess(accountManager.modify(me));
    }


    @Override
    public B loginOut() {
        String token = RequestContext.getToken();
        Long accountId = CacheUtil.getIdByToken();
        if(accountId == null){
            return B.create(ErrorCode.NO_LOGIN.reMsg());
        }
        return B.checkSuccess(CacheUtil.delKey(token));
    }


}
